#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "mqtt_client.h"
#include "my_uart.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "string.h"
#include "driver/gpio.h"
#include "CRC16.h"
#include "wifi.h"
#include "cJSON.h"
#include "get_time.h"
#include "mbedtls/md5.h"
#include "my_wss.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "my_nvs.h"
#include <math.h>
#include <time.h>
#define TAG1 "N2O_UART"

const int RX_BUF_SIZE = 1024;
const int N2O_RX_SIZE = 1024;
TaskHandle_t N2OSyncOnceHandle = NULL;
TaskHandle_t N2OSyncWeekHandle = NULL;
#define TXD_PIN (GPIO_NUM_4)
#define RXD_PIN (GPIO_NUM_5)
#define N2O_TXD_PIN (GPIO_NUM_14)
#define N2O_RXD_PIN (GPIO_NUM_13)
#define N2O_RTS_PIN (GPIO_NUM_12)
#define N2O_CTS_PIN (UART_PIN_NO_CHANGE)
#define N2O_UART_NUM UART_NUM_1
// Read packet timeout
#define N2O_PACKET_READ_TICS (100 / portTICK_PERIOD_MS)
char N2OSyncOnce_flag = 0; // 一次性策略定时任务创建标志位
char N2OSyncWeek_flag = 0; // 周期性策略定时任务创建标志位
char N2Oalarm_flag = 0;    // 浓度警报任务创建标志位
N2OSyncPolicy N2O_Sync;
char N2O_address = 0x01;   // N2O初始地址为1。
int N2O_concentration = 0; // N2O浓度
int alarmMaxValue = 0;     // N2O报警阈值
int first_read_N2O = 1;    // 第一次读取N2O浓度指数
// Timeout threshold for UART = number of symbols (~10 tics) with unchanged state on receive pin
#define N2O_READ_TOUT (3) // 3.5T * 8 = 28 ticks, TOUT=3 -> ~24..33 ticks

void myuart_init(void)
{
    const uart_config_t uart0_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    uart_driver_install(UART_NUM_2, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
    uart_param_config(UART_NUM_2, &uart0_config);
    uart_set_pin(UART_NUM_2, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}

int sendData(const char *logName, const char *data)
{
    const int len = strlen(data);
    const int txBytes = uart_write_bytes(UART_NUM_2, data, len); // 返回推送的字节数
    ESP_LOGI(logName, "Wrote %d bytes", txBytes);
    return txBytes;
}

void tx_task(void *arg)
{
    static const char *TX_TASK_TAG = "TX_TASK";
    esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
    while (1)
    {
        sendData(TX_TASK_TAG, "Hello");
        vTaskDelay(2000);
    }
}

void rx_task(void *arg)
{
    static const char *RX_TASK_TAG = "RX_TASK";
    esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
    uint8_t *data = (uint8_t *)malloc(RX_BUF_SIZE + 1);
    while (1)
    {
        const int rxBytes = uart_read_bytes(UART_NUM_2, data, RX_BUF_SIZE, 1000);
        if (rxBytes > 0)
        {
            data[rxBytes] = 0;
            ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rxBytes, data);
            ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
        }
    }
    free(data);
}

// 负氧离子传感器串口初始化
void N2O_uart_init(void)
{

    const int n2o_uart_num = N2O_UART_NUM;
    const uart_config_t n2o_uart_config = {
        .baud_rate = 9600,
        .data_bits = UART_DATA_8_BITS,
        .parity = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_DEFAULT,
    };
    ESP_LOGI(TAG1, "Start RS485 application test and configure UART.");

    // 安装UART驱动程序
    ESP_ERROR_CHECK(uart_driver_install(n2o_uart_num, N2O_RX_SIZE, 0, 0, NULL, 0)); // intr_alloc_flags 用于分配中断的标志。一个或多个（ORred）

    // 设置uart参数
    ESP_ERROR_CHECK(uart_param_config(n2o_uart_num, &n2o_uart_config));
    // 设置uart引脚
    ESP_ERROR_CHECK(uart_set_pin(n2o_uart_num, N2O_TXD_PIN, N2O_RXD_PIN, N2O_RTS_PIN, N2O_CTS_PIN));
    // 设置为RS485半双工模式
    ESP_ERROR_CHECK(uart_set_mode(n2o_uart_num, UART_MODE_RS485_HALF_DUPLEX));
    // Set read timeout of UART TOUT feature
    ESP_ERROR_CHECK(uart_set_rx_timeout(n2o_uart_num, N2O_READ_TOUT));
}

// N2O传感器发送数据
void N2O_send(const int port, const char *str, uint8_t length)
{
    if (uart_write_bytes(port, str, length) != length)
    {
        ESP_LOGE(TAG1, "Send data critical failure.");
        // 在此处添加处理发送失败的代码
        // abort();
    }
}

// 修改N2O传感器地址
char N2O_set_address(char address)
{

    ESP_LOGI(TAG1, "Start change N2O Address");
    if (address < 1 || address > 254)
    {
        ESP_LOGE(TAG1, "Address Number Error.");
        return 0;
    }
    char data[] = {0x01, 0x10, 0x30, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00};
    char checkdata[] = {0x01, 0x10, 0x30, 0x00, 0x00, 0x01, 0x00, 0x00}; // 用来比对返回报文的正确性
    data[0] = N2O_address;                                               // 更改前的地址
    data[8] = address;                                                   // 更改后的地址
    unsigned short crc16 = CRC16((unsigned char *)data, sizeof(data) / sizeof(data[0]));
    data[9] = (char)(crc16 >> 8);
    data[10] = (char)(crc16);

    checkdata[0] = N2O_address;
    crc16 = CRC16((unsigned char *)checkdata, sizeof(checkdata) / sizeof(checkdata[0]));
    checkdata[6] = (char)(crc16 >> 8);
    checkdata[7] = (char)(crc16);
    // 发送指令
    N2O_send(N2O_UART_NUM, data, sizeof(data) / sizeof(data[0]));

    char *cbdata = (char *)malloc(N2O_RX_SIZE); // 申请返回报文的空间
    // 从UART读取返回报文
    int len = uart_read_bytes(N2O_UART_NUM, cbdata, N2O_RX_SIZE, N2O_PACKET_READ_TICS);
    if (len > 0)
    {
        int result = memcmp(checkdata, cbdata, len);
        if (result == 0)
        {
            ESP_LOGI(TAG1, "Change N2O Address Success.");
            N2O_address = address;
            free(cbdata);
            return 1;
        }
        else
        {
            ESP_LOGI(TAG1, "Change N2O Address Error.");
            free(cbdata);
            return 0;
        }
    }
    free(cbdata);
    return 0;
}

// 读取负氧离子浓度
int Read_N2O_concentration(void)
{
    ESP_LOGI(TAG1, "start read N2O Concentration");

    char data[] = {0x01, 0x03, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00}; // 读取指令，最后两位用来存储校验值
    data[0] = N2O_address;
    unsigned short crc16 = CRC16((unsigned char *)data, sizeof(data) / sizeof(data[0]) - 2);
    data[6] = (char)(crc16);
    data[7] = (char)(crc16 >> 8);

    ESP_LOGI(TAG1, "data[6] = %02X,data[7] = %02X", data[6], data[7]);

    N2O_send(N2O_UART_NUM, data, 8);

    char *cbdata = (char *)malloc(N2O_RX_SIZE);
    // 从UART读取返回报文
    int len = uart_read_bytes(N2O_UART_NUM, cbdata, N2O_RX_SIZE, N2O_PACKET_READ_TICS);
    if (len > 0)
    {
        unsigned short crc16 = CRC16((unsigned char *)cbdata, len - 2);
        if (cbdata[0] != N2O_address || cbdata[1] != 0x03 || cbdata[5] != (char)(crc16) || cbdata[6] != (char)(crc16 >> 8))
        {
            ESP_LOGE(TAG1, "Read N2O Concentration Error");
            free(cbdata); // 释放内存
            cbdata = NULL;
            return 0;
        }
        else // 报文正确{}
        {
            for (size_t i = 0; i < 9; i++)
            {
                printf("cbdata[%d] = %02x  ", i, cbdata[i]);
            }
            printf("\n");
            unsigned short N2O_Con = (cbdata[3] << 8) | (cbdata[4] & 0xFF);
            // printf("\ncbdata[2] = %x,cbdata[3] = %x,cbdata[4] = %x\n", cbdata[2], cbdata[3], cbdata[4]);
            printf("N2O_Con:%d\n", N2O_Con);
            printf("\r\nN2O_Con: %04X\n", N2O_Con);

            char hexString[5];
            sprintf(hexString, "%04X", N2O_Con);
            sscanf(hexString, "%X", &N2O_concentration);

            // 将数值乘以十后才是真实数值
            N2O_concentration *= 10;

            ESP_LOGI(TAG1, "Read N2O Concentration Success: The concentration is %d.", N2O_concentration);

            free(cbdata);
            cbdata = NULL;
            return 1;
        }
    }
    if (cbdata != NULL)
    {
        free(cbdata);
        cbdata = NULL;
    }
    return 0;
}

// 当负氧离子状态改变上报任务
void N2O_Change_task(N2O_change_Task_Params *params)
{
    int ret;
    int last_N2O = 0;
    while (1)
    {
        if (first_read_N2O)
        {
            ret = Read_N2O_concentration();
            if (ret)
            {
                ESP_LOGI(TAG1, "N2O_First_Read_Success");
                last_N2O = N2O_concentration;
                first_read_N2O = 0;
            }
            else // 读取失败
            {
                ESP_LOGI(TAG1, "N2O_First_Read_Error");
            }
        }
        else // 不是第一次读取N2O浓度
        {
            ret = Read_N2O_concentration();
            if (ret)
            {
                if ((N2O_concentration > last_N2O - params->inaccuracie) && (N2O_concentration < last_N2O + params->inaccuracie))
                {
                    ESP_LOGI(TAG1, "N2O_Not_Change");
                }
                else
                {
                    ESP_LOGI(TAG1, "N2O_Change:%d", N2O_concentration);
                    last_N2O = N2O_concentration; // 保留这次的读数
                    Publish_N2O_Change(params);
                }
            }
        }
        vTaskDelay(3000 / portTICK_PERIOD_MS);
    }
}
// 发布N2O状态改变报文
void Publish_N2O_Change(N2O_change_Task_Params *params)
{
    mbedtls_md5_context md5_ctx;
    char wait_encrypt_str[255] = {0};
    unsigned char decrypt[16];
    char decrypt_cs[33];
    char N2O_CON[6] = {0};
    char inaccuracie[6];
    cJSON *attributes = cJSON_CreateObject();
    cJSON *content;
    cJSON *sub_content;
    cJSON_AddStringToObject(attributes, "deviceType", "N2Osensor");
    cJSON_AddStringToObject(attributes, "subType", "GateWayBle");
    cJSON_AddStringToObject(attributes, "deviceMAC", mac_str);
    cJSON_AddStringToObject(attributes, "familyId", "0");
    cJSON_AddStringToObject(attributes, "groupId", "0");
    cJSON_AddStringToObject(attributes, "operate", "report");
    // content对象
    cJSON_AddItemToObject(attributes, "content", content = cJSON_CreateObject());
    cJSON_AddStringToObject(content, "type", "sensor");
    // 内部content
    cJSON_AddItemToObject(content, "content", sub_content = cJSON_CreateArray());

    cJSON *item_tmp = cJSON_CreateObject();
    sprintf(N2O_CON, "%d", N2O_concentration);
    cJSON_AddStringToObject(item_tmp, "concentration", N2O_CON);

    sprintf(inaccuracie, "%d", params->inaccuracie);
    cJSON_AddStringToObject(item_tmp, "inaccuracie", inaccuracie);
    // cJSON_AddNumberToObject(item_tmp, "concentration", N2O_concentration);

    cJSON_AddItemToArray(sub_content, item_tmp);
    char source[] = "Alive";
    cJSON_AddStringToObject(attributes, "source", source);
    cJSON_AddStringToObject(attributes, "version", "v0.1");
    get_time(&system_timestamp);
    char timestamp[14];
    sprintf(timestamp, "%lld", system_timestamp);
    cJSON_AddStringToObject(attributes, "timestamp", timestamp);
    // md5校验
    strcat(wait_encrypt_str, "Alive");
    strcat(wait_encrypt_str, source);
    strcat(wait_encrypt_str, timestamp);
    mbedtls_md5_init(&md5_ctx);
    mbedtls_md5_starts(&md5_ctx);
    mbedtls_md5_update(&md5_ctx, (unsigned char *)wait_encrypt_str, strlen((char *)wait_encrypt_str));
    mbedtls_md5_finish(&md5_ctx, decrypt);
    sprintf(decrypt_cs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", decrypt[0], decrypt[1], decrypt[2], decrypt[3], decrypt[4], decrypt[5], decrypt[6], decrypt[7], decrypt[8], decrypt[9],
            decrypt[10], decrypt[11], decrypt[12], decrypt[13], decrypt[14], decrypt[15]);
    mbedtls_md5_free(&md5_ctx);
    cJSON_AddStringToObject(attributes, "sign", (char *)decrypt_cs);
    cJSON_AddStringToObject(attributes, "append", (char *)json_append);
    char *ptr = cJSON_Print(attributes);
    // 打印出来
    ESP_LOGI(TAG1, "client publish:%s", ptr);
    // 发布
    int msg_id = esp_mqtt_client_publish(params->client, g_publish_topic, ptr, 0, 0, 0);
    ESP_LOGI(TAG1, "sent publish successful, msg_id=%d", msg_id);
    if (ptr != NULL)
    {
        cJSON_free(ptr);
        ptr = NULL;
    }
    cJSON_Delete(attributes);
}

// 发布传感器读到的数据
void Publish_N2O_concentration(esp_mqtt_client_handle_t *client)
{
    mbedtls_md5_context md5_ctx;
    char wait_encrypt_str[255] = {0};
    unsigned char decrypt[16];
    char decrypt_cs[33];
    char N2O_CON[6] = {0};

    cJSON *attributes = cJSON_CreateObject();
    cJSON *content;
    cJSON_AddStringToObject(attributes, "deviceType", "N2Osensor");
    cJSON_AddStringToObject(attributes, "subType", "GateWayBle");
    cJSON_AddStringToObject(attributes, "deviceMAC", mac_str);
    cJSON_AddStringToObject(attributes, "familyId", "0");
    cJSON_AddStringToObject(attributes, "groupId", "0");
    cJSON_AddStringToObject(attributes, "operate", "reply");

    // content对象
    cJSON_AddItemToObject(attributes, "content", content = cJSON_CreateObject());
    int ret = Read_N2O_concentration();
    if (ret)
    {
        cJSON_AddStringToObject(content, "msg", "success");
        sprintf(N2O_CON, "%d", N2O_concentration);
        cJSON_AddStringToObject(content, "concentration", N2O_CON);
    }
    else
    {
        cJSON_AddStringToObject(content, "msg", "failed");
        cJSON_AddStringToObject(content, "concentration", "NULL");
    }
    char source[] = "Alive";
    cJSON_AddStringToObject(attributes, "source", source);
    cJSON_AddStringToObject(attributes, "version", "v0.1");
    get_time(&system_timestamp);
    ESP_LOGI(TAG1, "The timestamp is %lld \n", system_timestamp);
    char timestamp[14];
    sprintf(timestamp, "%lld", system_timestamp);
    cJSON_AddStringToObject(attributes, "timestamp", timestamp);
    // md5校验
    strcat(wait_encrypt_str, "Alive");
    strcat(wait_encrypt_str, source);
    strcat(wait_encrypt_str, timestamp);
    mbedtls_md5_init(&md5_ctx);
    mbedtls_md5_starts(&md5_ctx);
    mbedtls_md5_update(&md5_ctx, (unsigned char *)wait_encrypt_str, strlen((char *)wait_encrypt_str));
    mbedtls_md5_finish(&md5_ctx, decrypt);
    sprintf(decrypt_cs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", decrypt[0], decrypt[1], decrypt[2], decrypt[3], decrypt[4], decrypt[5], decrypt[6], decrypt[7], decrypt[8], decrypt[9],
            decrypt[10], decrypt[11], decrypt[12], decrypt[13], decrypt[14], decrypt[15]);
    mbedtls_md5_free(&md5_ctx);
    cJSON_AddStringToObject(attributes, "sign", (char *)decrypt_cs);
    cJSON_AddStringToObject(attributes, "append", (char *)json_append);
    char *ptr = cJSON_Print(attributes);
    // 打印出来
    ESP_LOGI(TAG1, "client publish:%s", ptr);
    // 发布
    int msg_id = esp_mqtt_client_publish(client, g_publish_topic, ptr, 0, 0, 0);
    ESP_LOGI(TAG1, "sent publish successful, msg_id=%d", msg_id);
    if (ptr != NULL)
    {
        cJSON_free(ptr);
        ptr = NULL;
    }
    cJSON_Delete(attributes);
}

// N2O定时上报任务
void N2O_Timed_task(N2O_timed_Task_Params *params)
{
    mbedtls_md5_context md5_ctx;
    char wait_encrypt_str[255] = {0};
    unsigned char decrypt[16];
    char decrypt_cs[33];
    char N2O_CON[6] = {0};
    char interval[8] = {0};
    static int count = 0;
    while (1)
    {
        if (params->interval != 0)
        {
            count += 100;
        }
        else
        {
            count = 0;
        }
        if ((count > params->interval - 100) && (count < params->interval + 100))
        {
            printf("params->interval = %d,count = %d\n", params->interval, count);
            count = 0;

            cJSON *attributes = cJSON_CreateObject();
            cJSON *content;
            cJSON *sub_content;

            cJSON_AddStringToObject(attributes, "deviceType", "N2Osensor");
            cJSON_AddStringToObject(attributes, "subType", "GateWayBle");
            cJSON_AddStringToObject(attributes, "deviceMAC", mac_str);
            cJSON_AddStringToObject(attributes, "familyId", "0");
            cJSON_AddStringToObject(attributes, "groupId", "0");
            cJSON_AddStringToObject(attributes, "operate", "report");
            // content对象
            cJSON_AddItemToObject(attributes, "content", content = cJSON_CreateObject());
            cJSON_AddStringToObject(content, "type", "sensor");
            // 内部content
            cJSON_AddItemToObject(attributes, "content", sub_content = cJSON_CreateArray());

            cJSON *item_tmp = cJSON_CreateObject();
            cJSON_AddStringToObject(content, "mode", "Timedreport");
            int ret = Read_N2O_concentration();
            sprintf(N2O_CON, "%d", N2O_concentration);
            cJSON_AddStringToObject(item_tmp, "concentration", N2O_CON);

            sprintf(interval, "%d", params->interval);
            cJSON_AddStringToObject(item_tmp, "interval", interval);

            cJSON_AddItemToArray(sub_content, item_tmp);
            char source[] = "Alive";
            cJSON_AddStringToObject(attributes, "source", source);
            cJSON_AddStringToObject(attributes, "version", "v0.1");
            get_time(&system_timestamp);
            char timestamp[14];
            sprintf(timestamp, "%lld", system_timestamp);
            cJSON_AddStringToObject(attributes, "timestamp", timestamp);
            // md5校验
            strcat(wait_encrypt_str, "Alive");
            strcat(wait_encrypt_str, source);
            strcat(wait_encrypt_str, timestamp);
            mbedtls_md5_init(&md5_ctx);
            mbedtls_md5_starts(&md5_ctx);
            mbedtls_md5_update(&md5_ctx, (unsigned char *)wait_encrypt_str, strlen((char *)wait_encrypt_str));
            mbedtls_md5_finish(&md5_ctx, decrypt);
            sprintf(decrypt_cs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", decrypt[0], decrypt[1], decrypt[2], decrypt[3], decrypt[4], decrypt[5], decrypt[6], decrypt[7], decrypt[8], decrypt[9],
                    decrypt[10], decrypt[11], decrypt[12], decrypt[13], decrypt[14], decrypt[15]);
            mbedtls_md5_free(&md5_ctx);
            cJSON_AddStringToObject(attributes, "sign", (char *)decrypt_cs);
            cJSON_AddStringToObject(attributes, "append", (char *)json_append);
            char *ptr = cJSON_Print(attributes);
            // 打印出来
            ESP_LOGI(TAG1, "client publish:%s", ptr);
            // 发布
            int msg_id = esp_mqtt_client_publish(params->client, g_publish_topic, ptr, 0, 0, 0);
            ESP_LOGI(TAG1, "sent publish successful, msg_id=%d", msg_id);
            if (ptr != NULL)
            {
                cJSON_free(ptr);
                ptr = NULL;
            }
            cJSON_Delete(attributes);
        }
        vTaskDelay(10);
    }
}
// 测试
void N2O_TEST(void)
{
    // char data[] = {0x01, 0x10, 0x30, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00};
    // char checkdata[] = {0x01, 0x10, 0x30, 0x00, 0x00, 0x01, 0x00, 0x00}; // 用来比对返回报文的正确性
    // data[0] = N2O_address;                                               // 更改前的地址
    // unsigned short crc16 = CRC16((unsigned char *)data, sizeof(data) / sizeof(data[0]));
    // data[9] = (char)(crc16 >> 8);
    // data[10] = (char)(crc16);
    // // 发送指令
    // N2O_send(N2O_UART_NUM, data, sizeof(data) / sizeof(data[0]));
    char *cbdata = (char *)malloc(N2O_RX_SIZE); // 申请返回报文的空间

    // 从UART读取返回报文
    int len = uart_read_bytes(N2O_UART_NUM, cbdata, N2O_RX_SIZE, N2O_PACKET_READ_TICS);
    if (len > 0)
    {
        N2O_send(N2O_UART_NUM, cbdata, len);
    }
    free(cbdata);
    cbdata = NULL;
}

// 存储同步策略的各项参数
int N2O_SyncPolicy_Save(myCJson *data)
{
    static const char *TAG = "N2O_SyncPolicy";
    nvs_handle_t my_handle;
    esp_err_t err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
    err = nvs_set_str(my_handle, "Policy_Type", data->sub_type);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Policy_Type set error!!!");
        return 0;
    }
    if (strcmp(data->sub_type, "onetime") == 0) // 如果策略是 onetime
    {
        // 创建用于存储日期和时间的结构体
        struct tm tm;
        // 拼接日期和时间字符串
        char dateTimeStr[30] = "";
        snprintf(dateTimeStr, sizeof(dateTimeStr), "%s %s", data->sub_date, data->sub_time);
        if (strptime(dateTimeStr, "%Y-%m-%d %H:%M:%S", &tm) == NULL)
        {
            printf("日期时间格式错误\n");
            return 0;
        }
        printf("dateTimeStr = %s", dateTimeStr);
        // 使用mktime函数将tm结构转换为时间戳
        if (tm.tm_sec < 0 || tm.tm_sec > 59 ||
            tm.tm_min < 0 || tm.tm_min > 59 ||
            tm.tm_hour < 0 || tm.tm_hour > 23 ||
            tm.tm_mon < 0 || tm.tm_mon > 11 ||
            tm.tm_mday < 1 || tm.tm_mday > 31)
        {
            printf("时间设置错误\n");
            return 0; // 任何一个条件不满足，结构体无效
        }
        time_t onetime_timestamp = mktime(&tm) - 28800;
        if (onetime_timestamp < 0)
        {
            printf("转换时间戳失败\n");
            return 0;
        }
        printf("onetime_timestamp = %d", (int)onetime_timestamp);
        get_time(&system_timestamp);
        if (onetime_timestamp < system_timestamp)
        {
            printf("时间设置错误\n");
            return 0;
        }
        // 存入BedSyncPolicy结构体中
        N2O_Sync.timestamp = onetime_timestamp;
    }
    else if (strcmp(data->sub_type, "onetimeWeek") == 0) // 如果策略是 onetimeWeek
    {
        int hours, minutes, seconds;
        strcpy(N2O_Sync.week_time, data->sub_time);
        sscanf(N2O_Sync.week_time, "%d:%d:%d", &hours, &minutes, &seconds);
        if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59)
        {
            printf("时间设置错误\n");
            return 0;
        }

        strcpy(N2O_Sync.week, data->sub_week);
        int weekMask = (int)strtol(N2O_Sync.week, NULL, 16);
        if (weekMask > 127 || weekMask == 0)
        {
            printf("周询时间设置错误\n");
            return 0;
        }
    }
    else
    {
        printf("策略错误\n");
        return 0;
    }
    // 保存设备类型与设备ID
    int count = sizeof(data->sub_deviceType);
    strcpy(N2O_Sync.deviceType, data->sub_deviceType);
    count = sizeof(data->sub_deviceId);
    strcpy(N2O_Sync.deviceId, data->sub_deviceId);
    // 存储策略参数结构体
    count = sizeof(N2OSyncPolicy);
    err = nvs_set_blob(my_handle, "N2O_Sync", &N2O_Sync, count);
    if (err != ESP_OK)
    {
        nvs_close(my_handle);
        ESP_LOGE(TAG, "nvs_set_blob error!!!");
        return 0;
    }
    printf("Save state success!!!!\n");
    err = nvs_commit(my_handle);
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "nvs_commit error!!!");
        return 0;
    }
    nvs_close(my_handle);
    iterate_through_nvs();
    return 1;
}
void iterate_through_nvs(void)
{
    nvs_handle_t my_handle;
    esp_err_t err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
    if (err != ESP_OK)
    {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    }
    else
    {
        nvs_iterator_t it = NULL;
        err = nvs_entry_find("nvs", N2O_Storage, NVS_TYPE_ANY, &it);

        // 确保nvs_entry_find成功
        if (err != ESP_OK)
        {
            printf("Error (%s) finding first NVS entry!\n", esp_err_to_name(err));
            nvs_close(my_handle);
            return;
        }

        while (it != NULL)
        {
            nvs_entry_info_t info;
            err = nvs_entry_info(it, &info); // 检查这步是否成功
            if (err != ESP_OK)
            {
                printf("Error (%s) getting NVS entry info!\n", esp_err_to_name(err));
                break;
            }

            printf("key '%s', type '%02x' \n", info.key, info.type);
            // 根据类型读取并打印值
            switch (info.type)
            {
            case NVS_TYPE_I32:
            {
                int32_t value;
                nvs_get_i32(my_handle, info.key, &value);
                printf("Value (int32): %ld\n", (long)value);
                break;
            }
            case NVS_TYPE_STR:
            {
                size_t required_size;
                nvs_get_str(my_handle, info.key, NULL, &required_size);
                char *value = malloc(required_size);
                nvs_get_str(my_handle, info.key, value, &required_size);
                printf("Value (string):%s: %s\n", info.key, value);
                free(value);
                break;
            }
            case NVS_TYPE_BLOB:
            {
                size_t required_size;
                nvs_get_blob(my_handle, info.key, NULL, &required_size);
                char *value = malloc(required_size);
                nvs_get_blob(my_handle, info.key, value, &required_size);
                printf("Value (blob): %s\n", value);

                for (size_t i = 0; i < (required_size); i++)
                {
                    printf("%s[%d] = %d\n", info.key, i, value[i]);
                }
                free(value);
                break;
            }
            // 添加其他类型的处理...
            default:
                printf("Unsupported type\n");
            }

            // 正确更新迭代器
            err = nvs_entry_next(&it);
            if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND)
            {
                printf("Error (%s) nvs_entry_next!\n", esp_err_to_name(err));
                break;
            }
            if (it == NULL)
            {
                break; // 如果没有更多条目，则退出循环
            }
        }
        printf("iterate ok!!!\n");
        if (it != NULL)
        {
            nvs_release_iterator(it); // 确保最后释放迭代器
        }
    }
    nvs_close(my_handle);
}

// 一次性策略定时任务
void N2O_SyncPolicy_OneTime_Task(void *arg)
{
    printf("OneTime_Task_in!!!\n");
    nvs_handle_t my_handle;
    size_t required_size = 0;
    N2OSyncPolicy N2O_Start_Sync;
    // 任务创建标志位置1
    esp_err_t err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
    N2OSyncOnce_flag = 1;
    nvs_set_i8(my_handle, "N2OSyncOnce_flag", N2OSyncOnce_flag);
    err = nvs_commit(my_handle);
    nvs_close(my_handle);

    while (1)
    {
        esp_err_t err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
        if (err != ESP_OK)
        {
            printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
            nvs_close(my_handle);
        }
        // 获取策略控制参数
        required_size = 0;
        err = nvs_get_blob(my_handle, "N2O_Sync", NULL, &required_size);
        if (err != ESP_OK || required_size != sizeof(N2OSyncPolicy))
        {
            nvs_close(my_handle);
            printf("get_N2O_Sync_Error!!!\n");
        }
        else
        {
            err = nvs_get_blob(my_handle, "N2O_Sync", &N2O_Start_Sync, &required_size);
            if (err != ESP_OK)
            {
                nvs_close(my_handle);
                printf("get_N2O_Sync_Error!!!\n");
            }
        }
        nvs_close(my_handle);

        get_time(&system_timestamp);
        printf("system_timestamp = %lld,N2O_Start_Sync.timestamp = %lld\n", system_timestamp, N2O_Start_Sync.timestamp);
        if (system_timestamp - 3 < N2O_Start_Sync.timestamp && N2O_Start_Sync.timestamp < system_timestamp + 3) // 如果到达执行时间
        {

            Publish_N2O_concentration(my_client);
            // 任务创建标志位置0
            err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
            N2OSyncOnce_flag = 0;
            nvs_set_i8(my_handle, "N2OSyncOnce_flag", N2OSyncOnce_flag);
            err = nvs_commit(my_handle);
            nvs_close(my_handle);
            printf("Mission accomplished\n");
            vTaskDelete(NULL);
        }
        else if ((system_timestamp - N2O_Start_Sync.timestamp > 4) && (system_timestamp > N2O_Start_Sync.timestamp))
        {
            printf("miss time!!!\n");
            // 任务创建标志位置0
            err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
            N2OSyncOnce_flag = 0;
            nvs_set_i8(my_handle, "N2OSyncOnce_flag", N2OSyncOnce_flag);
            err = nvs_commit(my_handle);
            nvs_close(my_handle);
            printf("Mission Falied\n");
            Publish_Reply_Message(my_client, false, "OneTime");
            vTaskDelete(NULL);
        }
        else
        {
            printf("Time is not yet up.\n");
        }
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}

// 周轮询定时任务
void N2O_SyncPolicy_OneTimeWeek_Task(void *arg)
{

    printf("OneTimeWeek_Task_in!!!\n");
    // char timeStr[10]; // HH:MM:SS 需要8个字符 + 1个null终止符
    struct tm *tm;
    nvs_handle_t my_handle;
    esp_err_t err;
    N2OSyncPolicy N2O_Start_Sync;
    int hours, minutes, seconds;
    // 任务创建标志位置1
    err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
    N2OSyncWeek_flag = 1;
    nvs_set_i8(my_handle, "N2OSyncWeek_flag", N2OSyncWeek_flag);
    err = nvs_commit(my_handle);
    nvs_close(my_handle);

    while (1)
    {
        err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
        size_t required_size = 0;
        if (err != ESP_OK)
        {
            printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
            nvs_close(my_handle);
        }
        // 获取控制参数
        required_size = 0;
        err = nvs_get_blob(my_handle, "N2O_Sync", NULL, &required_size);
        if (err != ESP_OK || required_size != sizeof(N2OSyncPolicy))
        {
            nvs_close(my_handle);
            printf("get_N2O_Sync_Error!!!\n");
        }
        else
        {
            err = nvs_get_blob(my_handle, "N2O_Sync", &N2O_Start_Sync, &required_size);
            if (err != ESP_OK)
            {
                nvs_close(my_handle);
                printf("get_N2O_Sync_Error!!!\n");
            }
        }
        nvs_close(my_handle);
        required_size = 0;
        sscanf(N2O_Start_Sync.week_time, "%d:%d:%d", &hours, &minutes, &seconds);

        get_time(&system_timestamp);
        time_t timestamp = (time_t)system_timestamp;
        tm = localtime(&timestamp);
        tm->tm_hour += 8;
        int weekMask = (int)strtol(N2O_Start_Sync.week, NULL, 16);
        // snprintf(timeStr, sizeof(timeStr), "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
        printf("tm_hour = %d,tm_min = %d,tm_sec = %d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
        printf("hours = %d,minutes = %d,seconds = %d\n", hours, minutes, seconds);
        if ((weekMask & (1 << tm->tm_wday)) != 0)
        {
            printf("任务日，今天是星期%d\n", tm->tm_wday);
            if (tm->tm_hour == hours && tm->tm_min == minutes && (seconds > (tm->tm_sec - 2) && seconds < (tm->tm_sec + 2))) // 到达指定时间
            {
                printf("到达指定时间\n");
                Publish_N2O_concentration(my_client);
                printf("Mission accomplished\n");
                // vTaskDelete(NULL);
                vTaskDelay(5000 / portTICK_PERIOD_MS);
            }
        }
        else
        {
            printf("非任务日\n");
        }
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}

// 同步策略任务开启或关闭
int N2O_SyncPolicy_TaskKey(void)
{
    printf("N2O_SyncPolicy_TaskKey in!!!\n");
    nvs_handle_t my_handle;
    esp_err_t err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
    // 读取策略任务创建状态标志位
    size_t count = 0;
    err = nvs_get_i8(my_handle, "N2OSyncOnce_flag", (int8_t *)&N2OSyncOnce_flag);
    if (err == ESP_ERR_NVS_NOT_FOUND)
    {
        nvs_set_i8(my_handle, "N2OSyncOnce_flag", N2OSyncOnce_flag);
        nvs_commit(my_handle);
    }
    err = nvs_get_i8(my_handle, "N2OSyncWeek_flag", (int8_t *)&N2OSyncWeek_flag);
    if (err == ESP_ERR_NVS_NOT_FOUND)
    {
        nvs_set_i8(my_handle, "N2OSyncWeek_flag", N2OSyncWeek_flag);
        nvs_commit(my_handle);
    }
    err = nvs_get_i8(my_handle, "N2OSyncOnce_flag", (int8_t *)&N2OSyncOnce_flag);
    err = nvs_get_i8(my_handle, "N2OSyncWeek_flag", (int8_t *)&N2OSyncWeek_flag);
    printf(" N2OSyncOnce_flag = %d, N2OSyncWeek_flag = %d\n", N2OSyncOnce_flag, N2OSyncWeek_flag);
    // 读取策略开关
    count = 0;
    err = nvs_get_str(my_handle, "policyEn", NULL, &count);
    if (err != ESP_OK || count == 0)
    {
        printf("Error (%s) getting size of policyEn or policyEn not found!\n", esp_err_to_name(err));
        nvs_close(my_handle);
        return 0; // 退出函数
    }
    char *policyEn = (char *)malloc(count);
    if (!policyEn)
    {
        printf("Failed to allocate memory for policyEn\n");
        nvs_close(my_handle);
        return 0; // 退出函数
    }
    err = nvs_get_str(my_handle, "policyEn", policyEn, &count);
    printf("policyEn = %s\n", policyEn);
    if (err != ESP_OK)
    {
        printf("Error (%s) reading policyEn!\n", esp_err_to_name(err));
        free(policyEn);
        nvs_close(my_handle);
        return 0; // 退出函数
    }
    // 获取要开关的策略类型
    count = 0;
    err = nvs_get_str(my_handle, "policyEnType", NULL, &count);
    char entype[count];
    err = nvs_get_str(my_handle, "policyEnType", entype, &count);
    if (err != ESP_OK)
    {
        printf("Error (%s) reading Policy_Type!\n", esp_err_to_name(err));
        nvs_close(my_handle);
        return 0; // 退出函数
    }
    // 读取一次性定时策略时间
    count = 0;
    nvs_get_blob(my_handle, "N2O_Sync", NULL, &count);
    N2OSyncPolicy N2O_Key_Sync;
    nvs_get_blob(my_handle, "N2O_Sync", &N2O_Key_Sync, &count);
    //  根据报文，开启或关闭策略任务
    if (strcmp(policyEn, "enable") == 0)
    {
        printf("policyEn is enable\n");
        free(policyEn);
        if (strcmp(entype, "onetime") == 0)
        {
            // 判断策略时间是否过时
            get_time(&system_timestamp);
            if ((system_timestamp - N2O_Key_Sync.timestamp > 4) && (system_timestamp > N2O_Key_Sync.timestamp))
            {
                printf("Missing the scheduled time\n");
                nvs_close(my_handle);
                return 0; // 退出函数
            }
            if (N2OSyncOnce_flag == 0)
            {
                printf("创建同步一次策略任务\n");
                N2OSyncOnce_flag = 1;
                xTaskCreate(N2O_SyncPolicy_OneTime_Task, "N2O_SyncPolicy_OneTime_Task", 4096, NULL, 18, &N2OSyncOnceHandle);
                if (N2OSyncOnce_flag == 0)
                {
                    return 0;
                }
            }
            else
            {
                printf("同步一次策略任务已被创建过\n");
            }
        }
        if (strcmp(entype, "onetimeWeek") == 0)
        {
            if (N2OSyncWeek_flag == 0)
            {
                printf("创建同步周期策略任务\n");
                xTaskCreate(N2O_SyncPolicy_OneTimeWeek_Task, "N2O_SyncPolicy_OneTimeWeek_Task", 4096, NULL, 2, &N2OSyncWeekHandle);
                N2OSyncWeek_flag = 1;
            }
            else
            {
                printf("同步周期策略任务已被创建过\n");
            }
        }
    }
    else if (strcmp(policyEn, "disable") == 0)
    {
        printf("policyEn is disable\n");
        free(policyEn);
        if (strcmp(entype, "onetime") == 0)
        {
            if (N2OSyncOnce_flag == 1)
            {
                printf("删除同步一次策略任务\n");
                vTaskDelete(N2OSyncOnceHandle);
                N2OSyncOnce_flag = 0;
            }
            else
            {
                printf("同步一次策略任务未被创建\n");
            }
        }
        if (strcmp(entype, "onetimeWeek") == 0)
        {
            if (N2OSyncWeek_flag == 1)
            {
                printf("删除同步周期策略任务\n");
                vTaskDelete(N2OSyncWeekHandle);
                N2OSyncWeek_flag = 0;
            }
            else
            {
                printf("同步周期策略任务未被创建\n");
            }
        }
    }
    // 更新标志位
    err = nvs_set_i8(my_handle, "N2OSyncOnce_flag", N2OSyncOnce_flag);
    err = nvs_set_i8(my_handle, "N2OSyncWeek_flag", N2OSyncWeek_flag);
    err = nvs_commit(my_handle);
    nvs_close(my_handle);
    return 1;
}

// 报警任务开启或关闭
int N2O_Alarm_TaskKEY(void)
{
    printf("N2O_Alarm_TaskKEY in!!!\n");
    nvs_handle_t my_handle;
    size_t count = 0;
    esp_err_t err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);

    // // 读取策略任务创建状态标志位
    // err = nvs_get_i8(my_handle, "N2Oalarm_flag", (int8_t *)&N2Oalarm_flag);
    // // 如果还未存储
    // if (err == ESP_ERR_NVS_NOT_FOUND)
    // {
    //     nvs_set_i8(my_handle, "N2Oalarm_flag", N2Oalarm_flag);
    //     nvs_commit(my_handle);
    // }
    // 读取alarmEn
    count = 0;
    err = nvs_get_str(my_handle, "alarmEn", NULL, &count);
    if (err != ESP_OK || count == 0)
    {
        printf("Error (%s) getting size of alarmEn or alarmEn not found!\n", esp_err_to_name(err));
        nvs_close(my_handle);
        return 0; // 退出函数
    }
    char alarmEn[count];
    memset(alarmEn, 0, sizeof(alarmEn));
    err = nvs_get_str(my_handle, "alarmEn", alarmEn, &count);
    printf("alarmEn = %s\n", alarmEn);
    if (err != ESP_OK)
    {
        printf("Error (%s) reading alarmEn!\n", esp_err_to_name(err));
        nvs_close(my_handle);
        return 0; // 退出函数
    }

    if (strcmp(alarmEn, "enable") == 0)
    {
        if (N2Oalarm_flag == 0)
        {
            printf("创建N2O报警任务\n");
            // N2Oalarm_flag = 1;
            xTaskCreate(N2O_Alarm_Task, "N2O_Alarm_Task", 4096, NULL, 20, &N2OAlarmHandle);
        }
        else
        {
            printf("N2O报警任务已被创建过\n");
        }
    }
    else if (strcmp(alarmEn, "disable") == 0)
    {
        printf("alarmEn is disable\n");
        if (N2Oalarm_flag == 1)
        {
            printf("删除N2O报警任务\n");
            vTaskDelete(N2OAlarmHandle);
            N2Oalarm_flag = 0;
        }
        else
        {
            printf("N2O报警任务未被创建\n");
        }
    }
    // 更新标志位
    err = nvs_set_i8(my_handle, "N2Oalarm_flag", N2Oalarm_flag);
    err = nvs_commit(my_handle);
    nvs_close(my_handle);
    return 1;
}

// N2O警报任务
void N2O_Alarm_Task(void *arg)
{
    printf("N2O Alarm Task in!!!\n");
    nvs_handle_t my_handle;
    esp_err_t err;
    int ret;
    size_t count;
    char alarmMaxValue_str[count];
    memset(alarmMaxValue_str, 0, sizeof(alarmMaxValue_str));
    // 标志位置1
    N2Oalarm_flag = 1;
    err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
    nvs_set_i8(my_handle, "N2Oalarm_flag", N2Oalarm_flag);
    err = nvs_commit(my_handle);
    nvs_close(my_handle);

    while (1)
    {
        // 读取警报阈值
        err = nvs_open(N2O_Storage, NVS_READWRITE, &my_handle);
        count = 0;
        err = nvs_get_str(my_handle, "alarmMaxValue", NULL, &count);
        if (err != ESP_OK || count == 0)
        {
            printf("Error (%s) getting size of alarmMaxValue or alarmMaxValue not found!\n", esp_err_to_name(err));
            nvs_close(my_handle);
        }
        err = nvs_get_str(my_handle, "alarmMaxValue", alarmMaxValue_str, &count);
        if (err != ESP_OK)
        {
            printf("Error (%s) reading alarmMaxValue!\n", esp_err_to_name(err));
            nvs_close(my_handle);
        }
        alarmMaxValue = safe_atoi(alarmMaxValue_str);
        nvs_close(my_handle);

        ret = Read_N2O_concentration();
        if (ret == 0)
        {
            printf("读取错误\n");
        }
        else
        {
            printf("阈值为:%d,浓度为%d\n", alarmMaxValue, N2O_concentration);
        }

        // printf("阈值为:%d,浓度为%d\n", alarmMaxValue, N2O_concentration);
        if (N2O_concentration > alarmMaxValue)
        {
            printf("浓度超过阈值\n");
            // printf("阈值为:%d,浓度为%d\n", alarmMaxValue, N2O_concentration);
            Publish_N2O_Alarm(my_client);
        }
        vTaskDelay(3000 / portTICK_PERIOD_MS);
    }
}

// 发布N2O警报json报文
void Publish_N2O_Alarm(esp_mqtt_client_handle_t *client)
{
    mbedtls_md5_context md5_ctx;
    char wait_encrypt_str[255] = {0};
    unsigned char decrypt[16];
    char decrypt_cs[33];
    char N2O_CON[6] = {0};
    char N2O_Alarm[6] = {0};
    cJSON *attributes = cJSON_CreateObject();
    cJSON *content;
    cJSON *sub_content;
    cJSON_AddStringToObject(attributes, "deviceType", "N2Osensor");
    cJSON_AddStringToObject(attributes, "subType", "GateWayBle");
    cJSON_AddStringToObject(attributes, "deviceMAC", mac_str);
    cJSON_AddStringToObject(attributes, "familyId", "0");
    cJSON_AddStringToObject(attributes, "groupId", "0");
    cJSON_AddStringToObject(attributes, "operate", "report");
    // content对象
    cJSON_AddItemToObject(attributes, "content", content = cJSON_CreateObject());
    cJSON_AddStringToObject(content, "type", "N2Oalarm");
    // 内部content
    cJSON_AddItemToObject(content, "content", sub_content = cJSON_CreateArray());

    cJSON *item_tmp = cJSON_CreateObject();
    // 添加具体时间
    get_time(&system_timestamp);
    char timeStr[30];
    time_t rawtime = (time_t)system_timestamp;
    struct tm *timeinfo = localtime(&rawtime);
    timeinfo->tm_hour += 8;
    strftime(timeStr, 30, "%Y/%m/%d %H:%M:%S", timeinfo);
    cJSON_AddStringToObject(item_tmp, "timeStr", timeStr);
    // 添加alarmMaxValue
    sprintf(N2O_Alarm, "%d", alarmMaxValue);
    cJSON_AddStringToObject(item_tmp, "alarmMaxValue", N2O_Alarm);

    // 添加concentration
    sprintf(N2O_CON, "%d", N2O_concentration);
    cJSON_AddStringToObject(item_tmp, "concentration", N2O_CON);

    cJSON_AddItemToArray(sub_content, item_tmp);
    char source[] = "Alive";
    cJSON_AddStringToObject(attributes, "source", source);
    cJSON_AddStringToObject(attributes, "version", "v0.1");
    get_time(&system_timestamp);
    char timestamp[14];
    sprintf(timestamp, "%lld", system_timestamp);
    cJSON_AddStringToObject(attributes, "timestamp", timestamp);
    // md5校验
    strcat(wait_encrypt_str, "Alive");
    strcat(wait_encrypt_str, source);
    strcat(wait_encrypt_str, timestamp);
    mbedtls_md5_init(&md5_ctx);
    mbedtls_md5_starts(&md5_ctx);
    mbedtls_md5_update(&md5_ctx, (unsigned char *)wait_encrypt_str, strlen((char *)wait_encrypt_str));
    mbedtls_md5_finish(&md5_ctx, decrypt);
    sprintf(decrypt_cs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", decrypt[0], decrypt[1], decrypt[2], decrypt[3], decrypt[4], decrypt[5], decrypt[6], decrypt[7], decrypt[8], decrypt[9],
            decrypt[10], decrypt[11], decrypt[12], decrypt[13], decrypt[14], decrypt[15]);
    mbedtls_md5_free(&md5_ctx);
    cJSON_AddStringToObject(attributes, "sign", (char *)decrypt_cs);
    cJSON_AddStringToObject(attributes, "append", (char *)json_append);
    char *ptr = cJSON_Print(attributes);
    // 打印出来
    ESP_LOGI(TAG1, "client publish:%s", ptr);
    // 发布
    int msg_id = esp_mqtt_client_publish(client, g_publish_topic, ptr, 0, 0, 0);
    ESP_LOGI(TAG1, "sent publish successful, msg_id=%d", msg_id);
    if (ptr != NULL)
    {
        cJSON_free(ptr);
        ptr = NULL;
    }
    cJSON_Delete(attributes);
}
// 恢复出厂设置

// // 下面写发布到主题上
// cJSON *attributes = cJSON_CreateObject();
// cJSON *content;
// cJSON *sub_content;
// cJSON_AddStringToObject(attributes, "deviceType", "N2Osensor");
// cJSON_AddStringToObject(attributes, "subType", "GateWayBle");
// cJSON_AddStringToObject(attributes, "deviceMAC", mac_str);
// cJSON_AddStringToObject(attributes, "familyId", "0");
// cJSON_AddStringToObject(attributes, "groupId", "0");
// cJSON_AddStringToObject(attributes, "operate", "report");
// // content对象
// cJSON_AddItemToObject(attributes, "content", content = cJSON_CreateObject());
// cJSON_AddStringToObject(content, "type", "sensor");
// // 内部content
// cJSON_AddItemToObject(attributes, "content", sub_content = cJSON_CreateArray());
// cJSON *item_tmp = cJSON_CreateObject();
// cJSON_AddNumberToObject(item_tmp, "concentration", N2O_concentration);
// cJSON_AddItemToArray(sub_content, item_tmp);
// char source[] = "Alive";
// cJSON_AddStringToObject(attributes, "source", source);
// cJSON_AddStringToObject(attributes, "version", "v0.1");
// get_time(&system_timestamp);
// char timestamp[13];
// sprintf(timestamp, "%lld", system_timestamp);
// cJSON_AddStringToObject(attributes, "timestamp", timestamp);
// // md5校验
// strcat(wait_encrypt_str, "Alive");
// strcat(wait_encrypt_str, source);
// strcat(wait_encrypt_str, timestamp);
// mN2Otls_md5_init(&md5_ctx);
// mN2Otls_md5_starts(&md5_ctx);
// mN2Otls_md5_update(&md5_ctx, (unsigned char *)wait_encrypt_str, strlen((char *)wait_encrypt_str));
// mN2Otls_md5_finish(&md5_ctx, decrypt);
// sprintf(decrypt_cs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", decrypt[0], decrypt[1], decrypt[2], decrypt[3], decrypt[4], decrypt[5], decrypt[6], decrypt[7], decrypt[8], decrypt[9],
//         decrypt[10], decrypt[11], decrypt[12], decrypt[13], decrypt[14], decrypt[15]);
// mN2Otls_md5_free(&md5_ctx);
// cJSON_AddStringToObject(attributes, "sign", (char *)decrypt_cs);
// char *ptr = cJSON_Print(attributes);
// // 打印出来
// ESP_LOGI(TAG1, "client publish:%s", ptr);
// // 发布
// int msg_id = esp_mqtt_client_publish(client, "ALIVE/CLIENT/GateWayBle/30c6f7f7a4d8", ptr, 0, 0, 0);
// ESP_LOGI(TAG1, "sent publish successful, msg_id=%d", msg_id);
// if (ptr != NULL)
// {
//     cJSON_free(ptr);
//     ptr = NULL;
// }
// cJSON_Delete(attributes);
// cJSON_Delete(content);
// cJSON_Delete(sub_content);
// cJSON_Delete(item_tmp);